package common

import (
	"ginEssential/model"
	"github.com/dgrijalva/jwt-go"
	"time"
)

var jwtKey = []byte("a_secret_crect")

//封装了 标准的jwt声明和自己额外添加的声明 UserID
type Claims struct {
	UserId uint
	jwt.StandardClaims
}

//token的意义主要在于不需要重新输入用户名和密码，但是无法避免服务端查库
/* 一共三部分 第一部分header信息 ，第二部分的声明信息 可以base64解码，注意，不要在JWT的payload或header中放置敏感信息，除非它们是加密的
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJVc2VySWQiOjEsImV4cCI6MTYzNjg4MzIzNSwiaWF0IjoxNjM2Mjc4NDM1LCJpc3MiOiJZYmwiLCJzdWIiOiJ1c2VyIHRva2VuIn0.
a0B5sP8bs04FtKnd0OxPekek83jGrr6TghllrcrcmO0"

{"alg":"HS256","typ":"JWT"}
{"UserId":1,"exp":1636883235,"iat":1636278435,"iss":"Ybl","sub":"user token"}
*/
func ReleaseToken(user model.User) (string, error) {
	//设置token的有效期 7天
	expirationTime := time.Now().Add(7 * 24 * time.Hour)
	//把要发送的信息初始化好
	Claims := &Claims{
		UserId: user.ID,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: expirationTime.Unix(),
			IssuedAt:  time.Now().Unix(),
			Issuer:    "Ybl",        //谁发放的
			Subject:   "user token", //发放的主题
		},
	}
	//把刚刚的内容加密使用JWT签名算法     这部分就是摘要 ，把内容+hash 生成摘要
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, Claims) //这里要HS256
	//使用我们自己设置的密钥来生成token ,后面也用该密钥来解密 属于是对称加密，摘要用这个密钥来加密 生成签名，最后返回tokenstring
	tokenString, err := token.SignedString(jwtKey)
	if err != nil {
		return "", err
	}
	return tokenString, nil
}

func ParseToken(tokenstring string) (*jwt.Token, *Claims, error) {
	claims := &Claims{}
	//这里相当于对tokenstring的第三部分的解密，前两部分是可以直接base64解密的，第三部分是加密过的
	token, err := jwt.ParseWithClaims(tokenstring, claims, func(token *jwt.Token) (interface{}, error) {
		return jwtKey, nil
	})
	//返回claim
	return token, claims, err

}
